using MediatR;
using Dapper;
using Microsoft.Extensions.Logging;
using RBAC.Domain.ArrivalInspection;
using RBAC.ErrorCode;
using RBAC.Interstructrue.Base;
using RBAC.Write.Api.Application.Command.ArrivalInspection;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace RBAC.Write.Api.Application.Handler.ArrivalInspection
{
    /// <summary>
    /// 新增到货检验 处理器
    /// </summary>
    public class CreateArrivalInspectionHandler : IRequestHandler<CreateArrivalInspectionCommand, APIResult<long>>
    {
        private readonly IBaseRepository<ArrivalInspectionInfo> _headerRepo;
        private readonly IDbConnectionFactory _connectionFactory;
        private readonly ILogger<CreateArrivalInspectionHandler> _logger;

        public CreateArrivalInspectionHandler(
            IBaseRepository<ArrivalInspectionInfo> headerRepo,
            IDbConnectionFactory connectionFactory,
            ILogger<CreateArrivalInspectionHandler> logger)
        {
            _headerRepo = headerRepo;
            _connectionFactory = connectionFactory;
            _logger = logger;
        }

        public Task<APIResult<long>> Handle(CreateArrivalInspectionCommand request, CancellationToken cancellationToken)
        {
            var res = new APIResult<long>();
            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (request == null)
                {
                    res.Code = APIEnums.Fail;
                    res.Msg = "请求为空";
                    res.Data = 0;
                    return Task.FromResult(res);
                }
                if (request.Items == null || request.Items.Count == 0)
                {
                    res.Code = APIEnums.Fail;
                    res.Msg = "明细不能为空";
                    res.Data = 0;
                    return Task.FromResult(res);
                }

                // 解析日期
                DateTime inspectionDate;
                if (!DateTime.TryParse(request.InspectionDate, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out inspectionDate))
                {
                    // 尝试只解析日期
                    if (!DateTime.TryParse(request.InspectionDate, out inspectionDate))
                    {
                        res.Code = APIEnums.Fail;
                        res.Msg = "检验日期格式不正确";
                        res.Data = 0;
                        return Task.FromResult(res);
                    }
                }

                // 生成唯一DocCode
                var now = DateTime.Now;
                string docCode = string.IsNullOrWhiteSpace(request.DocCode) ? GenerateDocCode(now) : request.DocCode!.Trim();
                if (!string.IsNullOrWhiteSpace(request.DocCode))
                {
                    var exists = _headerRepo.QueryFirstOrDefault<int>(
                        "SELECT COUNT(1) FROM ArrivalInspectionInfo WHERE DocCode = @DocCode AND IsDeleted = 0",
                        new { DocCode = docCode });
                    if (exists > 0)
                    {
                        res.Code = APIEnums.Fail;
                        res.Msg = "单号已存在";
                        res.Data = 0;
                        return Task.FromResult(res);
                    }
                }
                else
                {
                    // 唯一性重试
                    int retry = 0;
                    var rnd = new Random();
                    while (true)
                    {
                        var exists = _headerRepo.QueryFirstOrDefault<int>(
                            "SELECT COUNT(1) FROM ArrivalInspectionInfo WHERE DocCode = @DocCode",
                            new { DocCode = docCode });
                        if (exists == 0) break;
                        if (retry++ > 6) throw new InvalidOperationException("生成唯一单号失败，请重试");
                        docCode = $"AI{now:yyyyMMddHHmmss}{rnd.Next(0, 1000):D3}";
                    }
                }
                // 可选：采购日期解析
                DateTime? purchaseDate = null;
                if (!string.IsNullOrWhiteSpace(request.PurchaseDate))
                {
                    if (DateTime.TryParse(request.PurchaseDate, out var pd))
                    {
                        purchaseDate = pd;
                    }
                }

                var p = new Dictionary<string, object?>
                {
                    ["DocCode"] = docCode,
                    ["Subject"] = request.Subject?.Trim(),
                    ["InspectionDate"] = inspectionDate,
                    ["Inspector"] = request.Inspector ?? string.Empty,
                    ["Department"] = request.Department ?? string.Empty,
                    ["Remark"] = request.Remark ?? string.Empty,
                    ["PurchaseOrderNo"] = request.PurchaseOrderNo ?? string.Empty,
                    ["SupplierId"] = request.SupplierId ?? string.Empty,
                    ["SupplierName"] = request.SupplierName ?? string.Empty,
                    ["PurchaseDate"] = purchaseDate,
                    ["PurchaseContact"] = request.PurchaseContact ?? string.Empty,
                    ["ContactPhone"] = request.ContactPhone ?? string.Empty,
                    ["Buyer"] = request.Buyer ?? string.Empty,
                    ["PurchaseDept"] = request.PurchaseDept ?? string.Empty,
                    ["ProjectName"] = request.ProjectName ?? string.Empty,
                    ["DocStatus"] = 0,
                    ["BizStatus"] = 0,
                    ["Auditor"] = string.Empty,
                    ["AuditDate"] = null,
                    ["CreateUser"] = request.CreateUser,
                    ["CreateTime"] = now
                };

                long newId = 0;
                // 显式事务，分步执行，确保在同一连接上回滚/提交
                using (var conn = _connectionFactory.CreateConnectionWithRetry())
                {
                    using (var tran = conn.BeginTransaction())
                    {
                        try
                        {
                            // 插入单头
                            _logger?.LogInformation("Creating ArrivalInspection header DocCode={DocCode}, Subject={Subject}, DocStatus={DocStatus}, BizStatus={BizStatus}", p["DocCode"], p["Subject"], p["DocStatus"], p["BizStatus"]);
                            var insertHeaderSql = @"INSERT INTO ArrivalInspectionInfo
(DocCode, Subject, InspectionDate, Inspector, Department, Remark, PurchaseOrderNo, SupplierId, SupplierName, PurchaseDate, PurchaseContact, ContactPhone, Buyer, PurchaseDept, ProjectName, DocStatus, BizStatus, Auditor, AuditDate, CreateUser, CreateTime, IsDeleted)
VALUES
(@DocCode, @Subject, @InspectionDate, @Inspector, @Department, @Remark, @PurchaseOrderNo, @SupplierId, @SupplierName, @PurchaseDate, @PurchaseContact, @ContactPhone, @Buyer, @PurchaseDept, @ProjectName, @DocStatus, @BizStatus, @Auditor, @AuditDate, @CreateUser, @CreateTime, false);";
                            conn.Execute(insertHeaderSql, p, tran);
                            newId = conn.ExecuteScalar<long>("SELECT LAST_INSERT_ID();", transaction: tran);

                            // 插入明细
                            const string insertItemSql = @"INSERT INTO ArrivalInspectionItem 
(InspectionId, PurchaseOrderNo, MaterialCode, MaterialName, SpecModel, Unit, Brand, PurchaseQty, ReceivedQty, InspectionType, InspectQty, QualifiedQty, UnqualifiedQty, InspectResult, UnqualifiedReason, Remark)
VALUES
(@InspectionId, @PurchaseOrderNo, @MaterialCode, @MaterialName, @SpecModel, @Unit, @Brand, @PurchaseQty, @ReceivedQty, @InspectionType, @InspectQty, @QualifiedQty, @UnqualifiedQty, @InspectResult, @UnqualifiedReason, @Remark);";

                            for (int i = 0; i < request.Items.Count; i++)
                            {
                                var d = request.Items[i];
                                conn.Execute(insertItemSql, new
                                {
                                    InspectionId = newId,
                                    PurchaseOrderNo = d.PurchaseOrderNo ?? request.PurchaseOrderNo ?? string.Empty,
                                    MaterialCode = d.MaterialCode ?? string.Empty,
                                    MaterialName = d.MaterialName ?? string.Empty,
                                    SpecModel = d.SpecModel ?? string.Empty,
                                    Unit = d.Unit ?? string.Empty,
                                    Brand = d.Brand ?? string.Empty,
                                    PurchaseQty = d.PurchaseQty,
                                    ReceivedQty = d.ReceivedQty,
                                    InspectionType = d.InspectionType ?? string.Empty,
                                    InspectQty = d.InspectQty,
                                    QualifiedQty = d.QualifiedQty,
                                    UnqualifiedQty = d.UnqualifiedQty,
                                    InspectResult = d.InspectResult ?? string.Empty,
                                    UnqualifiedReason = d.UnqualifiedReason ?? string.Empty,
                                    Remark = d.Remark ?? string.Empty
                                }, tran);
                            }

                            // 插入附件（如有）
                            if (request.Attachments != null && request.Attachments.Count > 0)
                            {
                                const string insertAttSql = @"INSERT INTO ArrivalInspectionAttachment 
(InspectionId, FileName, FilePath, FileSize, UploadTime, Uploader, Remark)
VALUES
(@InspectionId, @FileName, @FilePath, @FileSize, @UploadTime, @Uploader, @Remark);";

                                for (int i = 0; i < request.Attachments.Count; i++)
                                {
                                    var a = request.Attachments[i];
                                    conn.Execute(insertAttSql, new
                                    {
                                        InspectionId = newId,
                                        FileName = a.FileName,
                                        FilePath = a.FilePath,
                                        FileSize = a.FileSize,
                                        UploadTime = ParseOrNow(a.UploadTime),
                                        Uploader = a.Uploader ?? request.CreateUser ?? string.Empty,
                                        Remark = a.Remark ?? string.Empty
                                    }, tran);
                                }
                            }

                            tran.Commit();
                        }
                        catch
                        {
                            try { tran.Rollback(); } catch { }
                            throw;
                        }
                    }
                }

                res.Code = APIEnums.Success;
                res.Msg = "新增到货检验成功";
                res.Data = newId;
            }
            catch (OperationCanceledException)
            {
                res.Code = APIEnums.Fail;
                res.Msg = "请求已取消";
                res.Data = 0;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "新增到货检验失败: {Message}", ex.Message);
                res.Code = APIEnums.Error;
                res.Msg = "新增到货检验失败";
                res.Data = 0;
            }

            return Task.FromResult(res);
        }

        private static string GenerateDocCode(DateTime now)
        {
            var rnd = new Random();
            return $"AI{now:yyyyMMddHHmmss}{rnd.Next(0, 100):D2}";
        }

        private static DateTime ParseOrNow(string? dt)
        {
            if (string.IsNullOrWhiteSpace(dt)) return DateTime.Now;
            if (DateTime.TryParse(dt, out var d)) return d;
            return DateTime.Now;
        }
    }
}
